package mcache

import (
	"gitee.com/dennis-mxx/mxx-core-v2/mbolt"
	"github.com/goccy/go-json"
)

type BoltCacheable struct {
	Cache      Cacheable
	Bolt       *mbolt.Bolt
	BucketName string
}

func (ce *BoltCacheable) Get(key string) (string, error) {
	if b, err := ce.GetBytes(key); IsError(err) {
		return "", err
	} else {
		return string(b), nil
	}
}
func (ce *BoltCacheable) GetFunc(key string, fun func() []byte) (string, error) {
	if res, err := ce.Get(key); IsError(err) {
		return "", err
	} else {
		if res == "" {
			b := fun()
			if err := ce.SetBytes(key, b); err != nil {
				return "", err
			} else {
				return string(b), nil
			}
		} else {
			return res, nil
		}
	}
}

func (ce *BoltCacheable) GetBytes(key string) ([]byte, error) {
	if b, err := ce.Cache.GetBytes(key); err == nil {
		if b == nil {
			if tran, err := ce.Bolt.R(); err == nil {
				defer tran.Rollback()
				return tran.Bucket(ce.BucketName).GetBytes(key), nil
			} else {
				return nil, err
			}

		} else {
			return b, nil
		}
	} else {
		return nil, err
	}
}
func (ce *BoltCacheable) GetBytesFunc(key string, fun func() []byte) ([]byte, error) {
	if res, err := ce.GetBytes(key); IsError(err) {
		return nil, err
	} else {
		if res == nil {
			b := fun()
			if err := ce.SetBytes(key, b); err != nil {
				return nil, err
			} else {
				return b, nil
			}
		} else {
			return res, nil
		}
	}
}
func (ce *BoltCacheable) Set(key string, value string) error {
	return ce.SetBytes(key, []byte(value))
}

func (ce *BoltCacheable) SetBytes(key string, value []byte) error {
	if err := ce.Cache.SetBytes(key, value); err == nil {

		if tran, err := ce.Bolt.RW(); err == nil {
			defer tran.Commit()
			return tran.Bucket(ce.BucketName).SetBytes(key, value)
		} else {
			return err
		}
	} else {
		return err
	}
}

func (ce *BoltCacheable) Delete(key string) error {
	if err := ce.Cache.Delete(key); err == nil {
		if tran, err := ce.Bolt.RW(); err == nil {
			defer tran.Commit()
			return tran.Bucket(ce.BucketName).Delete(key)
		} else {
			return err
		}
	} else {
		return err
	}
}

func (ce *BoltCacheable) GetJsonFunc(key string, dest any, fun func() []byte) (any, error) {
	if res, err := ce.GetJson(key, dest); err != nil {
		return nil, err
	} else {
		if res != nil {
			return res, nil
		}
		b := fun()
		if err := ce.SetBytes(key, b); err != nil {
			return nil, err
		}
		if err := json.Unmarshal(b, dest); err != nil {
			return nil, err
		}
		return dest, nil
	}
}

func (ce *BoltCacheable) GetJson(key string, dest any) (any, error) {
	if b, err := ce.GetBytes(key); IsError(err) {
		return nil, err
	} else {
		if b == nil {
			return nil, nil
		}
		if err := json.Unmarshal(b, dest); err == nil {
			return dest, nil
		} else {
			return nil, err
		}
	}
}

func (ce *BoltCacheable) SetJson(key string, dest any) error {
	if b, err := json.Marshal(dest); err == nil {
		return ce.SetBytes(key, b)
	} else {
		return err
	}
}

func (ce *BoltCacheable) Close() error {
	defer ce.Cache.Close()
	defer ce.Bolt.Bolt.Close()
	return nil
}
